<template>
  <div ref="container">
    <div>帧数：{{ framesPerSecond }}</div>
    <div class="buttonPanel">
      <div style="text-align: center">
        摄像机位置
        <div class="input-group">
          <div>
            <span> x：</span
            ><input
              type="number"
              class="posInput"
              v-model="cameraPos.x"
              min="-2600"
              max="2600"
            />
          </div>

          <input type="range" v-model="cameraPos.x" min="-2600" max="2600" />
        </div>
        <div class="input-group">
          <div>
            <span> y：</span
            ><input
              type="number"
              class="posInput"
              v-model="cameraPos.y"
              min="-3000"
              max="3000"
            />
          </div>

          <input type="range" v-model="cameraPos.y" min="-3000" max="3000" />
        </div>
        <div class="input-group">
          <div>
            <span> z：</span
            ><input
              type="number"
              class="posInput"
              v-model="cameraPos.z"
              min="-3000"
              max="3000"
            />
          </div>

          <input type="range" v-model="cameraPos.z" min="-3000" max="3000" />
        </div>
      </div>
      <div>
        <button @click="requestRandomCity">随机多层级城市</button>
        <button @click="loadOriginCity">单层城市</button>
        <div class="axis-container">
          x轴
          <div class="axis x"></div>
          y轴
          <div class="axis y"></div>
          z轴
          <div class="axis z"></div>
        </div>
      </div>
    </div>

    <div ref="canvas"></div>
  </div>
</template>

<script>
import axios from "axios";
import * as THREE from "three";
import { OrbitControls } from "three/examples/jsm/controls/OrbitControls.js";
import { TrackballControls } from "three/examples/jsm/controls/TrackballControls.js";
import { OBJLoader } from "three/examples/jsm/loaders/OBJLoader.js";
import { MTLLoader } from "three/examples/jsm/loaders/MTLLoader.js";
import CimScene from "../assets/class/CimScene";
import { initializeScene, updateScene } from "../assets/class/CimLod";
import CimEntity from "@/assets/class/CimEntity";

let scene = "";

let renderer = "";
let controls = "";
export default {
  data() {
    return {
      camera: "",
      light: "",
      directionalLight: "",
      width: window.innerWidth * 0.9,
      height: window.innerHeight * 0.9,
      lightHelper: "",
      frames: 0,
      times: 0,
      framesPerSecond: 0,
      clock: "",
      lod: "", //层次细节

      cimScene: "",
      cimList: [],
      cameraPos: { x: 0, y: 0, z: 0 },
    };
  },
  watch: {
    cameraPos: {
      handler() {
        //更新模型显示
        let newList = initializeScene(this.cameraPos, this.cimScene, 0);

        let addList = newList
          .filter(
            (itemNew) =>
              !this.cimList.some((itemOld) => itemNew.id === itemOld.id)
          )
          .slice();
        let deleteList = this.cimList
          .filter(
            (itemOld) => !newList.some((itemNew) => itemNew.id === itemOld.id)
          )
          .slice();

        deleteList.forEach((cimEntity) => {
          cimEntity.removeModel(scene);
        });

        addList.forEach((cimEntity) => {
          cimEntity.addModel(scene);
        });

        this.cimList = newList;

        //更新摄像机位置
        let watch = scene.getObjectByName("观察体");
        watch.position.set(
          this.cameraPos.x,
          this.cameraPos.y,
          this.cameraPos.z
        );
      },
      deep: true,
    },
    "camera.position": {
      handler() {
        if (this.viewMode == "first") {
          //修改视角
          this.cameraPos.x = this.camera.position.x;
          this.cameraPos.y = this.camera.position.y;
          this.cameraPos.z = this.camera.position.z;
        }
      },
      deep: true,
    },
  },
  async mounted() {
    THREE.Cache.enabled = true;
    //初始值
    this.cimScene = await this.createCimScene();
    //创建threejs中的场景、相机、渲染器
    let cim = this.cimScene.createScene(window.innerWidth, window.innerHeight);
    scene = cim.scene;
    this.camera = cim.camera;
    renderer = cim.renderer;

    //模型初次加载
    this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
    this.cimList.forEach((cimEntity) => {
      cimEntity.addModel(scene);
    });

    //摄像机位置设置
    this.loadObj(
      "观察体",
      "观察体",
      this.cameraPos.x,
      this.cameraPos.y,
      this.cameraPos.z
    );

    //地板
    this.loadObj("floor", "floor", 0, -3, 0);

    console.log(scene);

    while (this.$refs.canvas.firstChild) {
      this.$refs.canvas.removeChild(this.$refs.canvas.firstChild);
    }
    this.$refs.canvas.appendChild(renderer.domElement);
    controls = new OrbitControls(this.camera, renderer.domElement); //创建控件对象
    controls.mouseButtons = {
      LEFT: THREE.MOUSE.PAN,
      MIDDLE: THREE.MOUSE.DOLLY,
      RIGHT: THREE.MOUSE.ROTATE,
    };

    this.clock = new THREE.Clock();

    this.animate();
  },
  methods: {
    animate() {
      renderer.render(scene, this.camera);
      this.frames = this.frames + 1;
      let T = this.clock.getDelta();
      this.times = this.times + T;
      if (this.times >= 1) {
        this.framesPerSecond = Math.floor(this.frames / this.times);
        this.frames = 0;
        this.times = 0;
      }
      requestAnimationFrame(this.animate); //请求再次执行渲染函数render
    },

    loadObj(objname, mtlname, x, y, z) {
      var loader = new OBJLoader();
      var mloader = new MTLLoader();
      const cityGroup = new THREE.Object3D();
      cityGroup.name = objname;
      mloader.load("static/lodModel/" + mtlname + ".mtl", function (materials) {
        materials.preload();
        loader.setMaterials(materials);
        loader.load(
          "static/lodModel/" + objname + ".obj",
          function loadobj(obj) {
            obj.name = objname + "-";
            cityGroup.add(obj);
            cityGroup.position.set(x, y, z);
          }
        );
      });
      renderer.render(scene, this.camera);
      scene.add(cityGroup);
    },

    async createCimScene() {
      //这里生产环境有问题，无法请求/random-city
      let configData = await axios.get("/random-city").then(
        (response) => {
          // 请求成功时的处理
          console.log("成功获取数据");
          return response.data;
        },
        (error) => {
          // 请求失败时的处理
          console.error("获取数据失败:", error);

          return this.getLocalData();
        }
      );

      console.log(configData);
      let configScene = configData.scene;

      //创建数据结构的scene
      let cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      cimScene.loadEntity();
      console.log("cimScene", cimScene);

      return cimScene;
    },

    async getLocalData() {
      let localData = await fetch("static/cim2.json").then(
        (res) => {
          return res.json();
        },
        (err) => {
          console.log("本地json错误：" + err);
        }
      );

      return localData;
    },

    //清空场景模型
    clearScene() {
      this.cimList.forEach((cimEntity) => {
        cimEntity.removeModel(scene);
      });
    },

    async loadOriginCity() {
      let localData = await fetch("static/cim3.json").then((res) => {
        return res.json();
      });

      let configScene = localData.scene;

      //创建数据结构的scene
      this.cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      this.cimScene.loadEntity();
      console.log("cimScene", this.cimScene);
      //模型再次加载
      this.clearScene();
      this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
      this.cimList.forEach((cimEntity) => {
        cimEntity.addModel(scene);
      });
    },

    async requestRandomCity() {
      let localData = await axios.get("/random-city").then(
        (response) => {
          //刷新内容，这里先用浏览器重刷
          //window.location.reload(true);
          console.log("刷新后数据", response.data);
          return response.data;
        },
        (error) => {
          console.log(error.message);
          alert("无法连接至服务器，即将刷新页面");
          //刷新内容，这里先用浏览器重刷
          window.location.reload(true);
        }
      );

      let configScene = localData.scene;

      //创建数据结构的scene
      this.cimScene = new CimScene("scene_0001", {
        name: configScene.name,
        lodsetting: configScene.lodsetting,
        default_camera: configScene.default_camera,
        default_background: configScene.default_background,
        children: configScene.children,
      });
      this.cimScene.loadEntity();
      console.log("cimScene", this.cimScene);
      //模型再次加载
      this.clearScene();
      this.cimList = initializeScene(this.cameraPos, this.cimScene, 0);
      this.cimList.forEach((cimEntity) => {
        cimEntity.addModel(scene);
      });
    },
  },
  beforeDestroy() {
    //销毁内存中的模型
    THREE.Cache.clear();
  },
};
</script>

<style>
.buttonPanel {
  position: absolute;
  margin-top: 10px;
  display: flex;
  width: 400px;
  height: 200px;
  background-color: aqua;
}

.input-group {
  margin-right: 20px;
  text-align: center;
  display: flex;
  flex-direction: column;
}

.axis-container {
  display: flex;
  flex-direction: column;
  align-items: center;
  width: 50%;
  height: 300px;
 
}

.axis {
  width: 100%;
  height: 5px;
  margin: 10px 0;
}

.axis.x {
  background-color: #ff8c00; /* Orange for X-axis */
}

.axis.y {
  background-color: #4caf50; /* Green for Y-axis */
}

.axis.z {
  background-color: #2196f3; /* Blue for Z-axis */
}
</style>